% This is the standalone version of the paper

% Copyright (c)1994-1995, M. Welsh, mdw@cs.cornell.edu
% Unlimited distribution and modification of this work is permitted,
% as long as the original author is credited and the above copyright
% notice entact.

\chapter{\label{mdw}Porting Applications to Linux}
\author{Matt Welsh \\ {\tt mdw@cs.cornell.edu}}
\date{26 January 1995}

\section{Introduction}

Porting UNIX applications to the Linux operating system is remarkably
easy. Linux, and the GNU C library used by it, have been designed with
applications portability in mind, meaning that many applications will
compile simply by issuing {\tt make}. Those which don't generally
use some obscure feature of a particular implementation, or rely
strongly on undocumented or undefined behavior of, say, a particular
system call. 

Linux is mostly compliant with IEEE Std 1003.1-1988 (POSIX.1), but 
has not actually been certified as such. Similarly, Linux also 
implements many features found in the SVID and BSD strains of UNIX,
but again does not necessarily adhere to them in all cases. In general,
Linux has been designed to be compatible with other UNIX implementations,
to make applications porting easier, and in a number of instances has
improved upon or corrected behavior found in those implementations.

As an example, the {\em timeout\/} argument passed to the {\em select\/} 
system call is actually decremented during the poll operation by Linux. 
Other implementations don't modify this value at all, and applications
which aren't expecting this could break when compiled under Linux.
The BSD and SunOS man pages for {\em select\/} warn that 
in a ``future implementation'', the system call may modify the
timeout pointer. Unfortunately, many applications still assume
that the value will be untouched. 

The goal of this paper is to provide an overview of the major
issues associated with porting applications to Linux, highlighting
the differences between Linux, POSIX.1, SVID, and BSD in the 
following areas: signal handling, terminal I/O, process control
and information gathering, and portable conditional compilation. 

\section{Signal handling}

Over the years, the definition and semantics of signals have been 
modified in various ways by different implementations of UNIX.
Today, there are two major classes of symbols: {\em unreliable\/}
and {\em reliable}. Unreliable signals are those for which the
signal handler does not remain installed once called. These ``one-shot''
signals must re-install the signal handler within the signal handler
itself, if the program wishes the signal to remain installed. Because
of this, there is a race condition in which the signal can arrive 
again before the handler is re-installed, which can cause the signal
to either be lost or for the original behavior of the signal to be
triggered (such as killing the process). Therefore, these signals
are ``unreliable'' because the signal catching and handler re-installation
operations are nonatomic. 

Under unreliable signal semantics, system calls are not restarted
automatically when interrupted by a signal. Therefore, in order for
a program to account for all cases, the program would need to check
the value of {\em errno\/} after every system call, and reissue the
system call if its value is {\em EINTR}. 

Along similar lines, unreliable signal semantics don't provide
an easy way to get an atomic pause operation (put the process to
sleep until a signal arrives). Because of the unreliable nature of
reinstalling signal handlers, there are cases in which a signal can
arrive without the program realizing this. 

Under reliable signal semantics, on the other hand, the signal
handler remains installed when called, and the race condition for
reinstallation is avoided. Also, certain system calls can be
restarted, and an atomic pause operation is available via the
POSIX {\em sigsuspend\/} function.

\subsection{Signals under SVR4, BSD, and POSIX.1}

The SVR4 implementation of signals incorporates the functions
{\em signal}, {\em sigset}, {\em sighold}, {\em sigrelse}, {\em sigignore},
and {\em sigpause}. The {\em signal\/} function under SVR4 is 
identical to the classic UNIX V7 signals, providing only unreliable
signals. The other functions do provide signals with automatic
reinstallation of the signal handler, but no system call restarting
is supported. 

Under BSD, the functions {\em signal}, {\em sigvec}, {\em sigblock},
{\em sigsetmask}, and {\em sigpause} are supported. All of the functions
provide reliable signals with system call restarting by default, but
that behavior can be disabled if the programmer wishes.

Under POSIX.1, {\em sigaction}, {\em sigprocmask}, {\em sigpending},
and {\em sigsuspend} are provided. Note that there is no {\em signal}
function, and according to POSIX.1 it is depreciated. These functions
provide reliable signals, but system call restart behavior is not
defined by POSIX. If {\em sigaction} is used under SVR4 and BSD, 
system call restarting is disabled by default, but it can be turned
on if the signal flag {\tt SA\_RESTART} is specified. 

Therefore, the ``best'' way to use signals in a program is to use
{\em sigaction}, which allows you to explicitly specify the behavior
of signal handlers. However, {\em signal} is still used in many 
applications, and as we can see above {\em signal} provides different
semantics under SVR4 and BSD.

\subsection{Linux signal options}

The following values for the {\tt sa\_flags} member of the 
{\tt sigaction} structure are defined for Linux. 
\begin{itemize}
\item {\tt SA\_NOCLDSTOP}: Don't send {\tt SIGCHLD} when a child process
is stopped.
\item {\tt SA\_RESTART}: Force restart of certain system calls when
interrupted by a signal handler.
\item {\tt SA\_NOMASK}: Disable signal mask (which blocks signals during
execution of a signal handler).
\item {\tt SA\_ONESHOT}: Clear signal handler after execution. Note that
SVR4 uses {\tt SA\_RESETHAND} to mean the same thing.
\item {\tt SA\_INTERRUPT}: Defined under Linux, but unused. Under SunOS,
system calls were automatically restarted, and this flag disabled that
behavior.
\item {\tt SA\_STACK}: Currently a no-op, to be used for signal stacks.
\end{itemize}

Note that POSIX.1 defines only {\tt SA\_NOCLDSTOP}, and there are
several other options defined by SVR4 not available under Linux. 
When porting applications which use {\em sigaction}, you may have to
modify the values of {\tt sa\_flags} to get the appropriate behavior.

\subsection{{\em signal\/} under Linux}

Under Linux, the {\em signal\/} function is equivalent to using
{\em sigaction} with the {\tt SA\_ONESHOT} and {\tt SA\_NOMASK}
options; that is, it corresponds to the classic, unreliable
signal semantics as used under SVR4. 

If you wish {\em signal} to use BSD semantics, most Linux systems
provide a BSD compatibility library which can be linked with. To use
this library, you could add the options
\begin{verbatim}
  -I/usr/include/bsd -lbsd
\end{verbatim}
to the compilation command line. When porting applications using
{\em signal}, pay close attention to what assumptions the program makes
about use of signal handlers, and modify the code (or compile with the
appropriate definitions) to get the right behavior. 

\subsection{Signals supported by Linux}

Linux supports nearly every signal provided by SVR4, BSD, and POSIX, 
with few exceptions:
\begin{itemize}
\item {\tt SIGEMT} is not supported; it corresponds to a hardware fault
under SVR4 and BSD.
\item {\tt SIGINFO} is not supported; it is used for keyboard information
requests under SVR4.
\item {\tt SIGSYS} is not supported; it refers to an invalid system call
in SVR4 and BSD. If you link with {\tt libbsd}, this signal is redefined
to {\tt SIGUNUSED}.
\item {\tt SIGABRT} and {\tt SIGIOT} are identical.
\item {\tt SIGIO}, {\tt SIGPOLL}, and {\tt SIGURG} are identical.
\item {\tt SIGBUS} is defined as {\tt SIGUNUSED}. Technically there is
no ``bus error'' in the Linux environment. 
\end{itemize}

\section{Terminal I/O}

As with signals, terminal I/O control has three different implementations
under SVR4, BSD, and POSIX.1. 

SVR4 uses the {\tt termio} structure, and various {\em ioctl} calls 
(such as {\tt TCSETA}, {\tt TCGETA}, and so forth) on a terminal 
device to obtain and set parameters with the {\tt termio} structure.
This structure looks like:
\begin{verbatim}
  struct termio {
    unsigned short c_iflag;  /* Input modes */
    unsigned short c_oflag;  /* Output modes */
    unsigned short c_cflag;  /* Control modes */
    unsigned short c_lflag;  /* Line discipline modes */
    char c_line;             /* Line discipline */
    unsigned char c_cc[NCC]; /* Control characters */
  };
\end{verbatim}

Under BSD, the {\tt sgtty} structure is used with various {\em ioctl}
calls, such as {\tt TIOCGETP}, {\tt TIOCSETP}, and so forth.

Under POSIX, the {\tt termios} struct is used, along with various functions
defined by POSIX.1, such as {\em tcsetattr} and {\tt tcgetattr}. The
{\tt termios} structure is identical to {\tt struct termio} used by SVR4,
but the types are renamed (such as {\tt tcflag\_t} instead of {\tt unsigned
short}), and {\tt NCCS} is used for the size of the {\tt c\_cc} array.

Under Linux, both POSIX.1 {\em termios} and SVR4 {\em termio} are supported
directly by the kernel. This means that if your program uses either of
these methods for accessing terminal I/O, it should compile directly under
Linux. If you're ever in doubt, it's easy to modify code using 
{\tt termio} to use {\tt termios}, using a bit of knowledge of both
methods. Hopefully, this shouldn't ever be necessary. But, do pay attention
if a program attempts to use the {\tt c\_line} field in the {\tt termio}
structure. For nearly all applications, this should be {\tt N\_TTY}, and
if the program assumes that some other line discipline is available
you might have trouble.

If your program uses the BSD {\em sgtty} implementation, you can link
against {\tt libbsd.a} as described above. This will provide a replacement
for {\em ioctl} which will resubmit the terminal I/O requests in terms of
the POSIX {\tt termios} calls used by the kernel. When compiling such
a program, if symbols such as {\tt TIOCGETP} are undefined, you will
need to link against {\tt libbsd}. 

\section{Process information and control}

Programs such as {\em ps}, {\em top}, and {\tt free} must have some way
to obtain information from the kernel about a processes and system 
resources. Similarly, debuggers and other like tools need the ability
to control and inspect a running process. These features have been
provided by a number of interfaces by different versions of UNIX,
and nearly all of them are either machine-specific or tied to a
particular kernel design. So far, there has been no universally-accepted
interface for this kind of process-kernel interaction.

\subsection{{\em kvm} routines}

Many systems use routines such as {\em kvm\_open}, {\em kvm\_nlist},
and {\em kvm\_read} to access kernel data structures directly via
the {\em /dev/kmem} device. In general, these programs will open 
{\em /dev/kmem}, read the kernel's symbol table, locate data 
in the running kernel with this table, and read the appropriate 
addresses in the kernel address space with these routines. Because
this requires the user program and the kernel to agree upon the size
and format of data structures read in this fashion, such programs
often have to be rebuilt for each kernel revision, CPU type, and so
forth. 

\subsection{{\em ptrace} and the {\em /proc} filesystem}

The {\em ptrace} system call is used in 4.3BSD and SVID to control 
a process and read information from it. It is classically used by 
debuggers to, say, trap execution of a running process or examine
its state. Under SVR4, {\em ptrace} is superseded by the {\em /proc}
filesystem, which appears as a directory containing a single
file entry for each running process, named by process ID. The user
program can open the file corresponding to the process of interest
and issue various {\em ioctl} calls on it to control its execution
or obtain information from the kernel on the process. Similarly,
the program can read or write data directly in the process's 
address space through the file descriptor into the {\em /proc}
filesystem.

\subsection{Process control under Linux} 

Under Linux, the {\em ptrace} system call is supported for process
control, and it works as in 4.3BSD. To obtain process and system
information, Linux also provides a {\em /proc} filesystem, but with
very different semantics. Under Linux, {\em /proc} consists of a 
number of files providing general system information, such as
memory usage, load average, loaded module statistics, and network
statistics. These files are generally accessed using {\em read}
and {\em write} and their contents can be parsed using {\em scanf}.
The {\em /proc} filesystem under Linux also provides a directory 
entry for each running process, named by process ID, which
contains file entries for information such as the command line, links
to the current working directory and executable file, open file
descriptors, and so forth. The kernel provides all of this information
on the fly in response to {\em read} requests. This implementation
is not unlike the {\em /proc} filesystem found in Plan 9, but it
does have its drawbacks---for example, for a tool such as {\em ps}
to list a table of information on all running processes, many
directories must be traversed and many files opened and read. 
By comparison, the {\em kvm} routines used on other UNIX systems
read kernel data structures directly with only a few system calls.

Obviously, each implementation is so vastly different that porting
applications which use them can prove to be a real task. It should
be pointed out that the SVR4 {\em /proc} filesystem is a very
different beast than that found in Linux, and they may not be used
in the same context. Arguably, any program which uses the {\em kvm}
routines or SVR4 {\em /proc} filesystem is not really portable, and
those sections of code should be rewritten for each operating system.

The Linux {\em ptrace} call is nearly identical to that found in BSD,
but there are a few differences:
\begin{itemize}
\item The requests {\tt PTRACE\_PEEKUSER} and {\tt PTRACE\_POKEUSER} under
BSD are named {\tt PTRACE\_PEEKUSR} and {\tt PTRACE\_POKEUSR}, respectively,
under Linux.
\item Process registers can be set using the {\tt PTRACE\_POKEUSR} request
with offsets found in {\tt  /usr/include/linux/ptrace.h}.
\item The SunOS requests {\tt PTRACE\_\{READ,WRITE\}\{TEXT,DATA\}} are
not supported, nor are {\tt PTRACE\_SETACBKPT}, {\tt PTRACE\_SETWRBKPT},
{\tt PTRACE\_CLRBKPT}, or {\tt PTRACE\_DUMPCORE}.
These missing requests should only affect a small number of existing
programs.
\end{itemize}

Linux does {\em not} provide the {\em kvm} routines for reading the
kernel address space from a user program, but some programs (most
notably {\em kmem\_ps}) implement their own versions of these routines.
In general, these are not portable, and any code which uses the 
{\em kvm} routines is probably depending upon the availability of
certain symbols or data structures in the kernel---not a safe assumption
to make. Use of {\em kvm} routines should be considered architecture-specific.

\section{Portable conditional compilation}

If you need to make modifications to existing code in order to port
it to Linux, you may need to use {\tt ifdef}\ldots {\tt endif} pairs
to surround parts of Linux-specific code---or, for that matter, code
corresponding to other implementations. No real standard for selecting
portions of code to be compiled based on the operating system exists,
but many programs use a convention such as defining {\tt SVR4} for System
V code, {\tt BSD} for BSD code, and {\tt linux} for Linux-specific code.

The GNU C library used by Linux allows you to turn on various features
of the library by defining various macros at compile time. These
are:
\begin{itemize}
\item {\tt \_\_STRICT\_ANSI\_\_}: For ANSI C features only
\item {\tt \_POSIX\_SOURCE}: For POSIX.1 features
\item {\tt \_POSIX\_C\_SOURCE}: If defined as 1, POSIX.1 features;
if defined as 2, POSIX.2 features.
\item {\tt \_BSD\_SOURCE}: ANSI, POSIX, and BSD features.
\item {\tt \_SVID\_SOURCE}: ANSI, POSIX, and System V features.
\item {\tt \_GNU\_SOURCE}: ANSI, POSIX, BSD, SVID, and GNU extensions.
This is the default if none of the above are defined.
\end{itemize}

If you define {\tt \_BSD\_SOURCE} yourself, the additional definition
{\tt \_FAVOR\_BSD} will be defined for the library. This will
cause BSD behavior for certain things to be selected over POSIX or
SVR4. For example, if {\tt \_FAVOR\_BSD} is defined, {\em setjmp} and
{\em longjmp} will save and restore the signal mask, and {\em getpgrp}
will accept a PID argument. Note that you must still link against
{\tt libbsd} to get BSD-like behavior for the features mentioned 
earlier in this paper. 

Under Linux, {\tt gcc} defines a number of macros automatically
which you can use in your program. These are:
\begin{itemize}
\item {\tt \_\_GNUC\_\_} (major GNU C version, e.g., 2)
\item {\tt \_\_GNUC\_MINOR\_\_} (minor GNU C version, e.g., 5)
\item {\tt unix}
\item {\tt i386}
\item {\tt linux}
\item {\tt \_\_unix\_\_}
\item {\tt \_\_i386\_\_}
\item {\tt \_\_linux\_\_}
\item {\tt \_\_unix}
\item {\tt \_\_i386}
\item {\tt \_\_linux}
\end{itemize}
Many programs use 
\begin{verbatim}
  #ifdef linux
\end{verbatim} 
to surround Linux-specific code. Using these compile-time macros
you can easily adapt existing code to include or exclude changes
necessary to port the program to Linux, Note that because Linux
supports more System V-like features in general, the best code
base to start from with a program written for both System V and
BSD is probably the System V version. Alternately, you can start
from the BSD base and link against {\tt libbsd}. 

\section{Additional Comments} \footnote {Added by Sven Goldt}
This chapter covers most of the porting issues except the
missing system calls that are named in the system calls chapter
and the yet missing streams (rumors say a loadable stream module
should exist at ftp.uni-stuttgart.de in pub/systems/linux/isdn).


\endinput
